home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / bipl.zip / PROGS.ZIP / IIENCODE.ICN < prev    next >
Text File  |  1993-01-27  |  6KB  |  207 lines

  1. ############################################################################
  2. #
  3. #    File:     iiencode.icn
  4. #
  5. #    Subject:  Program to encode text in the style of uuencode
  6. #
  7. #    Author:   Richard L. Goerwitz
  8. #
  9. #    Date:     June 3, 1991
  10. #
  11. ###########################################################################
  12. #
  13. #    Version:  1.8
  14. #
  15. ###########################################################################
  16. #
  17. #  This is an Icon port of the UNIX/C uuencode utility.  Since
  18. #  uuencode is publicly distributable BSD code, I simply grabbed a
  19. #  copy, and rewrote it in Icon.  The only basic functional changes I
  20. #  made to the program were:  1) To simplify the notion of file mode
  21. #  (everything is encoded with 0644 permissions), and 2) to add sup-
  22. #  port for xxencode format (which will generally pass unscathed even
  23. #  through EBCDIC sites).
  24. #
  25. #  Iiencode's usage is compatible with that of the UNIX uuencode
  26. #  command, i.e. a first (optional) argument gives the name the file
  27. #  to be encoded.  If this is omitted, iiencode just uses the standard
  28. #  input.  The second argument specifies the name the encoded file
  29. #  should be given when it is ultimately decoded.
  30. #
  31. #  Extensions to the base uuencode command options include -x and -o.
  32. #  An -x tells iiencode to use xxencode (rather than uuencode) format.
  33. #  Option -o causes the following argument to be used as the file
  34. #  iiencode is to write its output to (the default is &output).  Note
  35. #  that, on systems with newline translation (e.g. MS-DOS), the -o
  36. #  argument should always be used.
  37. #
  38. #    iiencode [infile] [-x] remote-filename [-o] output-filename
  39. #
  40. #  BUGS:  Slow.  I decided to go for clarity and symmetry, rather than
  41. #  speed, and so opted to do things like use ishift(i,j) instead of
  42. #  straight multiplication (which under Icon v8 is much faster).  Note
  43. #  that I followed the format of the newest BSD release, which refuses
  44. #  to output spaces.  If you want to change things back around so that
  45. #  spaces are output, look for the string "BSD" in my comments, and
  46. #  then (un)comment the appropriate sections of code.
  47. #
  48. ############################################################################
  49. #
  50. #  See also: iidecode.icn
  51. #
  52. ############################################################################
  53.  
  54.  
  55. procedure main(a)
  56.  
  57.     local ofs, in_filename, out_filename, in, out, is_xx, remotename, usage
  58.  
  59.     usage := "usage:  iiencode [infile] [-x] _
  60.     remote-filename    [-o output-filename]"
  61.  
  62.     # Parse arguments.
  63.     ofs := 0
  64.     while (ofs +:= 1) <= *a do {
  65.         case a[ofs] of {
  66.         "-x"    : is_xx := 1
  67.         "-o"    : out_filename := a[ofs +:= 1] | stop(usage)
  68.         default : {
  69.         if not (/in_filename := a[ofs]) then
  70.             remotename := a[ofs]
  71.         }
  72.     }
  73.     }
  74.  
  75.     # If remotename is null, set it to in_filename.  If it's still
  76.     # null, then abort with usage message.
  77.     if /(/remotename :=: in_filename) then {
  78.         write(&errout,usage)
  79.         exit(2)
  80.     }
  81.  
  82.     # If no input filename was supplied, use &input.
  83.     if /in_filename then
  84.     /in := &input
  85.     else
  86.     in := open(in_filename) |
  87.     stop(&errout,"Can't open input file, ",in_filename,".\n",usage)
  88.  
  89.     # If an output filename was specified, open it for writing.
  90.     if \out_filename then
  91.     out := open(out_filename, "wu") |
  92.         stop("Can't open output file, ",out_filename,".\n",usage)
  93.     # Set null out to &output; advise DOS users to use -o option.
  94.     else {
  95.     out := &output
  96.     if find("MS-DOS",&features) then
  97.         write(&errout, "Okay, but the -o option is recommended for DOS.")
  98.     }
  99.  
  100.     # This generic version of uuencode treats file modes in a primitive
  101.     # manner so as to be usable in a number of environments.  Please
  102.     # don't get fancy and change this unless you plan on keeping your
  103.     # modified version on-site (or else modifying the code in such a
  104.     # way as to avoid dependence on a specific operating system).
  105.     writes(out, "begin 644 ",remotename,"\n")
  106.  
  107.     encode(out, in, is_xx)
  108.     writes(out, "end\n")
  109.  
  110.     every close(in|out)
  111.     exit(0)
  112.  
  113. end
  114.  
  115.  
  116.  
  117. procedure encode(out, in, is_xx)
  118.  
  119.     # Copy from in to standard output, encoding as you go along.
  120.  
  121.     local line
  122.  
  123.     if \is_xx then
  124.     ENC := xxENC
  125.  
  126.     # 1 (up to) 45 character segment
  127.     while line := reads(in, 45) do {
  128.     writes(out, ENC(*line))
  129.     line ? {
  130.         while outdec(move(3), out)
  131.         pos(0) | outdec(left(tab(0), 3, " "), out)
  132.     }
  133.     writes(out, "\n")
  134.     }
  135.     # Uuencode adds a space and newline here, which is decoded later
  136.     # as a zero-length line (signals the end of the decoded text).
  137.     # writes(" \n")
  138.     # The new BSD code (compatible with the old) avoids outputting
  139.     # spaces by writing a ` (see also how it handles ENC() below).
  140.     if \is_xx
  141.     then writes(out, "+\n")
  142.     else writes(out, "`\n")
  143.     
  144. end
  145.  
  146.  
  147.  
  148. procedure outdec(s, out)
  149.  
  150.     # Output one group of 3 bytes (s) to standard output.  This is one
  151.     # case where C is actually more elegant than Icon.  Note well!
  152.  
  153.     local c1, c2, c3, c4
  154.  
  155.     c1 := ishift(ord(s[1]),-2)
  156.     c2 := ior(iand(ishift(ord(s[1]),+4), 8r060),
  157.           iand(ishift(ord(s[2]),-4), 8r017))
  158.     c3 := ior(iand(ishift(ord(s[2]),+2), 8r074),
  159.           iand(ishift(ord(s[3]),-6), 8r003))
  160.     c4 := iand(ord(s[3]),8r077)
  161.     every writes(out, ENC(c1 | c2 | c3 | c4))
  162.  
  163.     return
  164.  
  165. end
  166.  
  167.  
  168.  
  169. procedure ENC(c)
  170.  
  171.     # ENC is the basic 1 character encoding procedure to make a char
  172.     # printing.
  173.  
  174.     # New BSD code doesn't output spaces...
  175.     return " " ~== char(iand(c, 8r077) + 32) | "`"
  176.     # ...the way the old code does:
  177.     # return char(iand(c, 8r077) + 32)
  178.  
  179. end
  180.  
  181.  
  182.  
  183. procedure xxENC(c)
  184.  
  185.     # ENC is the basic 1 character encoding procedure to make a char
  186.     # printing.
  187.  
  188.     local k, ordval, oversizes
  189.     static ordtbl
  190.     initial {
  191.     ordval := -1
  192.     ordtbl := table()
  193.     every k := !"+-0123456789ABCDEFGHIJKLMNOPQRST_
  194.              UVWXYZabcdefghijklmnopqrstuvwxyz"
  195.     do insert(ordtbl, ordval +:= 1, k)
  196.     oversizes := 0
  197.     }
  198.  
  199.     # Table lookup isn't the fastest ever, I know.  If I thought about
  200.     # it a bit longer, I'm sure I could do this using map.  This would
  201.     # require some type conversions, but I wonder whether it would still
  202.     # be substantially faster.  If anyone tries this out and times the
  203.     # results, please communicate to me the results!
  204.     return ordtbl[iand(c, 8r077)]
  205.  
  206. end
  207.